//
//      CGE - CRAb Graphics Engine
// 
//      Copyright (C) 2003-2009 by CRAb-UFC
//
//		This file is part of the "CRAb Graphics Engine"
//		See the copyright notice in cge.h for conditions of distribution and use.
//

#ifndef CGE_INETADDRESS_CLASS_H__
#define CGE_INETADDRESS_CLASS_H__

#include "Thread.h"

#define CGE_API
#define CGE_ERRF( expr ) std::cerr << expr << std::endl;
#define CGE_ERR( expr ) std::cerr << expr << std::endl;
#define CGE_LOG( expr ) std::cout << expr << std::endl;
#define CGE_LOGF( expr ) std::cout << expr << std::endl;

#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <arpa/inet.h>
    #include <fcntl.h>

namespace basterd
{


	typedef sockaddr_in __socketAddress;
	typedef int         __socket;

	typedef std::string String;
	typedef unsigned short mushort;
	typedef unsigned int muint;
	typedef unsigned int mubyte;

	namespace net
	{ 
		/** @brief Encapsulates an Internet Address, which can be used to setup servers and clients.
		 *
		 *  @see Socket, DatagramSocket
		 */
		class InetAddress
		{
			friend class DatagramSocket;
			friend class Socket;

		public:

			/**
			 * Constant address identifying the loopback, i.e., the local host.
			 */
			static const InetAddress INET_LOCALHOST;

			/**
			 * Constant address identifying the broadcast address, i.e., the local host.
			 */
			static const InetAddress INET_BROADCAST;
            
			/**
			 * Constructor
			 *
			 * @param hostAddress IP address of the desired host
			 */
			InetAddress( const String& hostAddress )
				: sinad(), address(hostAddress)
			{
				memset(&sinad,0,sizeof(sinad));
				sinad.s_addr = inet_addr( address.c_str() );
			}

			/**
			 * Constructor. Builds an address based on its IP address parts.
			 * For example, in the address "10.231.1.44":
			 *  - a corresponds to 10;
			 *  - b corresponds to 231;
			 *  - c corresponds to 1;
			 *  - d corresponds to 44;
			 *
			 * @param a First octet
			 * @param b Second octet 
			 * @param c Third octet
			 * @param d Fourth octet
			 */
			InetAddress( muint a, muint b, muint c, muint d  )
				: sinad(), address()
			{
				unsigned int iad = ( a << 24 ) | ( b << 16 ) | ( c << 8 ) | d;

				memset(&sinad,0,sizeof(sinad));
				sinad.s_addr = htonl( iad );
				address = inet_ntoa( sinad  );
			}

			/**
			 * Constructor. Builds from an existing low-level IP address
			 *
			 * @param rhs Built-in IP address
			 */
			InetAddress( const sockaddr_in& rhs )
				: sinad(rhs.sin_addr), address( inet_ntoa( rhs.sin_addr ) )
			{				
			}

			/**
			 * Copy-constructor
			 */
			InetAddress( const InetAddress& rhs )
				: sinad(rhs.sinad), address(rhs.address)
			{
			}

			/**
			 * Assignment operator
			 */
			InetAddress& operator = ( const InetAddress& rhs )
			{
				address = rhs.address;
				memcpy( &sinad, &rhs.sinad, sizeof(sinad));
				return *this;
			}

			/**
			 * Assignment operator from an existing IP and port address.
			 */
			InetAddress& operator = ( const sockaddr_in& rhs )
			{
				memcpy( &sinad, &rhs.sin_addr, sizeof(sinad));
				// human-readable address
				address = inet_ntoa( sinad  );
				return *this;
			}

			/**
			 * Assignment operator from an existing low-level address.
			 */
			InetAddress& operator = ( const in_addr& rhs )
			{
				memcpy( &sinad, &rhs, sizeof(in_addr));
				// human-readable address
				address = inet_ntoa( sinad  );
				return *this;
			}


			/**
			 * Converts this address to a "complete" socket address.
			 * 
			 * @param port IP port to be assigned to the sin parameter.
			 *
			 */
			sockaddr_in asSockAddress(mushort port) const
			{
				sockaddr_in sin;

				asSockAddress(sin,port);

				return sin;
			}

			/**
			 *  Converts this address to a "complete" socket address.
			 *
			 * @param sin [out] Destination socket address
			 * @param port IP port to be assigned to the sin parameter.
			 */
			void asSockAddress(sockaddr_in& sin, mushort port) const
			{
				memset(&sin,0, sizeof(sin));

				sin.sin_family = AF_INET;
				sin.sin_addr.s_addr = sinad.s_addr;
				sin.sin_port = htons(port);
			}

			/**
			 * Gets the human-readable address of this instance.
			 */
			const String& getAddress(void) const
			{
				return address;
			}

			/**
			 * Gets the low-level IP address of this instance.
			 */
			const in_addr& getSocketAddress(void) const
			{
				return sinad;
			}

			/**
			 *  Conversion to low-level socket address operator
			 */
			operator const in_addr& (void) const
			{
				return sinad;
			}


		protected:
		
			/**
			 *  Low-level IP address of this host.
			 */
		    in_addr sinad;

			/**
			 *  Human readable address of this host.
			 */
			String      address;

		}; // end of the InetAddress class

	}
}



#endif // CGE_SERVER_CLASS_H__
